/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sysRecmd;

import java.util.ArrayList;
import java.util.List;

import main.SYRRES;
import core.Review;
import core.SetReview;

/**
 * http://en.wikipedia.org/wiki/Perceptron
 * @author Le
 */
public class Perceptron {
    private SetReview trainReview;
    private SetReview testReview;
   
    private int noteID;
    private int numberOfConvergence;
    private int thresholdOfConvergence;
    
    // bias = 0
    // Learning rate alpha = 0.01
    private double alpha = 0.01;
    // Init Weights w
    private double[] w = new double[SYRRES.getContentSize()];
    // Input 
    private List<Integer> x = new ArrayList<Integer>();
    
    private boolean[] wFinal = new boolean[SYRRES.getContentSize()];
    
    // Les parametres pour le PERCEPTRON
    // Note reel
    private double z;
    // sum s
    private double s;
    // Error e
    private double e;
    
    public Perceptron (SetReview trainReview, SetReview testReview, 
    					int noteID, int numberOfConvergence, int thresholdOfConvergence) {
        this.trainReview = trainReview;
        this.testReview = testReview;
        this.noteID = noteID;
        this.numberOfConvergence = numberOfConvergence;
        this.thresholdOfConvergence = thresholdOfConvergence;
        
        for (int i = 0; i < wFinal.length; i++) {
        	wFinal[i] = false;
        	w[i] = 0;
        }
    }   
    
    public double[] trainReviews() {        
        // Step step
        int step = 0;
        Review review;
        
        while (true) {
        	for (int i = 0; i < trainReview.getReviews().size(); i++) {        		
        		review = trainReview.getReviews().get(i);
	        	x = review.getFreqArray();            
	            z = review.getNote(noteID);
	            
	            s = 0;
	            for (int j = 0; j < x.size(); j++) {
	                s += w[x.get(j)];
	            }
	            
	            e = z - s;          
	            
//	            if (z * s <= 0) {
		            for (int j = 0; j < x.size(); j++) {
		            	if (!wFinal[j]) {
		            		w[x.get(j)] += alpha * e;
		            	}
		            }	            
//	            }
        	}
        	
        	if (checkConvergence(step)) {
                System.out.println("done");
                
                for (int i = 0; i < w.length; i++) {
                    if (w[i] != 0) {
                        System.out.println("w " + i + " " + w[i]);
                    }
                }
                break;
            }   
        	
            step++;
        }        
        return w;
    }
    
    private boolean checkConvergence(int step) {
	   if (step != numberOfConvergence) {  
		   if (evaluer(step) < thresholdOfConvergence) {
			   return true;
		   } else {
			   return false;
		   }
	   } else {
		   return true;
	   }
   }

    public double evaluer(int step) {
    	double error_train = 0;
    	double error_test = 0;
    	double numberOfGoodNote = 0;
    	double numberOfNote = 0;
    	Review review;
    	
    	for (int i = 0; i < testReview.getReviews().size(); i++) {
    		review = testReview.getReviews().get(i);
    		
    		x = review.getFreqArray();            
            z = review.getNote(noteID);
             
            s = 0;
            for (int j = 0; j < x.size(); j++) {
            	s += w[x.get(j)];                
            }            	
            error_test += Math.pow(z - s, 2);
            /* Partie d'evaluation */
			numberOfNote++;
			// Si le note reel et le note prevu sont aussi positve (ou negative) => bon note prevu
			if (z * s > 0)	numberOfGoodNote++; 
			/* ------------------- */
    	}
    	
    	for (int i = 0; i < trainReview.getReviews().size(); i++) {        		
    		review = trainReview.getReviews().get(i);
        	x = review.getFreqArray();            
            z = review.getNote(noteID);
            
            s = 0;
            for (int j = 0; j < x.size(); j++) {
            	s += w[x.get(j)];                
            }
            error_train += Math.pow(z - s, 2);
    	}
    	
    	System.err.println("Step " + step + " error - train " + (error_train / trainReview.getReviews().size()) + 
    										      " - test " + (error_test / testReview.getReviews().size()));
    	System.out.println("Pourcentage des bons notes : " + ((float)numberOfGoodNote / numberOfNote * 100) + "%");		
    	return error_train;
    }
    
    
    public List<String> getPositive_NegativeWords(int numOfWords, boolean isPositive) {
    	ArrayList<String> posWords = new ArrayList<String>();
    	int[] posWordsIndex = new int[numOfWords];
    	double[] posWordsCoeff = new double[numOfWords];
    	
    	for (int i = 0; i < w.length; i++) {
    		for (int j = 0; j < posWordsIndex.length; j++) {
    			if ((isPositive && w[i] > posWordsCoeff[j]) || (!isPositive && w[i] < posWordsCoeff[j])) {
    				for (int k = posWordsIndex.length - 1; k > j ; k--) {
    					posWordsIndex[k] = posWordsIndex[k-1];
    					posWordsCoeff[k] = posWordsCoeff[k-1];
    				}
    				posWordsIndex[j] = i;
    				posWordsCoeff[j] = w[i];
    				break;
    			}
    		}
    	}
    	
    	for (int i = 0; i < posWordsIndex.length; i++) {
    		posWords.add(SYRRES.getContent(posWordsIndex[i]));
    		System.out.println(SYRRES.getContent(posWordsIndex[i]));
    	}
    	
    	return posWords;
    }
}
